/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package saltocaballo.expertos;

import java.awt.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import saltocaballo.comunes.logger;
import saltocaballo.entidades.Casilla;
import saltocaballo.entidades.Tablero;

/**
 *
 * @author Martinoxs
 */
public class Backtracking implements Busqueda{

    movimientosCaballo movimientos;
    Tablero tablero;
    logger log;
    
    public Backtracking(){
        movimientos = new movimientosCaballo();
    }
    
    @Override
    public String resolver(Tablero tablero, String metodo, logger logg) {
        
        this.tablero = tablero;
        String rdo = "";
        boolean sinSolucion = false;
        boolean consistente = false;
        log = logg;
        int iteraciones = 0;
        iniciarLog(metodo);
        
        String casillaElegida = tablero.getCasillaInicio().getCoordenada();
        String casillaAnterior = "Ninguna";
        String casillaProx = "Ninguna";
        tablero.ocuparCasilla(casillaElegida);
        tablero.setTieneCaballo(casillaElegida, true);
        
        Map<String, List<String>> movsCasillas = new HashMap<String, List<String>>();
        Map<String, List<String>> movsProhibidos = new HashMap<String, List<String>>();
        List<String> listaRdo = new ArrayList<String>();
        
        movsCasillas = recargarMovimientos(movsCasillas, metodo);       
        
        while(!tablero.tableroResuelto(tablero.getCopiaPanel()) && !sinSolucion){
            
            if(casillaElegida.equals("Ninguna") && casillaAnterior.equals("Ninguna")) {
                sinSolucion = true;
            }
            
            log.escribirLinea("----------------------------------------");
            log.escribirLinea("Iteracion: " + iteraciones + "  - CasillaActual: " + casillaElegida + " - CasillaAnterior: " + casillaAnterior + "    - CasillaProx: " + casillaProx);
            if(movsCasillas.get(casillaElegida).isEmpty()){
                log.escribirLinea("    - Movimientos(" + casillaElegida + "): vacío");
            } else {
                for(String s: movsCasillas.get(casillaElegida)){
                    log.escribirLinea("    - Movimientos(" + casillaElegida + "): " + s);
                }
            }
            log.escribirLinea("");
            if(listaRdo.isEmpty()){
                log.escribirLinea("    - MovimientosRdo: vacío");
            } else {
                for(String s: listaRdo){
                    log.escribirLinea("    - MovimientosRdo: " + s);
                }
            }
            log.escribirLinea("");
            log.escribirLinea("");
            
            for(Map.Entry<String,List<String>> mov: movsProhibidos.entrySet()){
                for(String m: mov.getValue()){
                    log.escribirLinea("    - MovimientosProhibidos(" + mov.getKey() + "): " + m);
                }
            }
            
            iteraciones++;
            
            casillaAnterior = casillaElegida;
            tablero.setTieneCaballo(casillaAnterior, false);
            
            if (!movsCasillas.get(casillaElegida).isEmpty()){
                casillaElegida = movsCasillas.get(casillaElegida).get(0);
            } else {
                sinSolucion = true;
                break;
            }
            tablero.ocuparCasilla(casillaElegida);
            tablero.setTieneCaballo(casillaElegida, true);
        
            
            log.escribirLinea("Elijo Casilla: " + casillaElegida + ", ocupar");
            log.escribirLinea("CasillaAnterior: " + casillaAnterior);
            listaRdo.add(casillaAnterior);
            log.escribirLinea("    * Agrego a MovimientosRdo: " + casillaAnterior);
            
            if(tablero.tableroResuelto(tablero.getCopiaPanel())){
                listaRdo.add(casillaElegida);
                break;
            }
            
            if(!movsCasillas.get(casillaElegida).isEmpty()){
                
                //listaMovs = movsCasillas.get(casillaElegida);
                movsCasillas = recargarMovimientos(movsCasillas, metodo);
                
            } else {
                
                log.escribirLinea("    * Casilla " + casillaElegida + " sin movimientos, volver atras");
                listaRdo.remove(listaRdo.size() - 1);
                log.escribirLinea("    * Remuevo " + casillaElegida + " de MovimientosRdo");
                movsCasillas.get(casillaAnterior).remove(movsCasillas.get(casillaAnterior).indexOf(casillaElegida));
                log.escribirLinea("         * Remuevo " + casillaElegida + " de los movimientos de " + casillaAnterior);
                
                agregarCasProhibida(casillaAnterior, casillaElegida, movsProhibidos);
                log.escribirLinea("    * Agrego " + casillaElegida + ", a MovimientosProhibidos de: " + casillaAnterior);
                
                boolean hayMovs = false;
                while(!hayMovs){
                    tablero.desocuparCasilla(casillaElegida, tablero.getCopiaPanel());
                    tablero.setTieneCaballo(casillaElegida, false);
                    log.escribirLinea("    * Desocupo casillaElegida: " + casillaElegida);
                    
                    agregarCasProhibida(casillaAnterior, casillaElegida, movsProhibidos);
                    log.escribirLinea("    * Agrego " + casillaElegida + ", a MovimientosProhibidos de: " + casillaAnterior);
                    
                    casillaElegida = casillaAnterior;
                    log.escribirLinea("    * Nueva casillaElegida: " + casillaElegida);
                    
                    if(casillaElegida.equals("Ninguna") && casillaAnterior.equals("Ninguna")) {
                        sinSolucion = true;
                        break;
                    }
                    
                    if (movsProhibidos.containsKey(casillaElegida)){
                        List<String> casillasProhibida = movsProhibidos.get(casillaElegida);
                        for(String casillaP: casillasProhibida){
                            if (movsCasillas.get(casillaElegida).contains(casillaP)){
                                movsCasillas.get(casillaElegida).remove(movsCasillas.get(casillaElegida).indexOf(casillaP));
                                log.escribirLinea("        * Remuevo " + casillaP + ", de los movimientos de " + casillaElegida);
                            }
                        }
                    }
                    
                    if(!listaRdo.isEmpty()){
                        casillaAnterior = listaRdo.get(listaRdo.size()-1);
                    } else {
                        casillaAnterior = "Ninguna";
                    }
                    
                    log.escribirLinea("    * CasillaAnterior: " + casillaAnterior);
                    
                    if(!movsCasillas.get(casillaElegida).isEmpty()){
                        hayMovs = true;
                        log.escribirLinea("    * Casilla con movimientos encontrada: " + casillaElegida);
                    } else {
                        
                        log.escribirLinea("    * Casilla " + casillaElegida + " sin movimientos, volver atras");
                        
                        if(movsProhibidos.containsKey(casillaElegida)){
                            movsProhibidos.remove(casillaElegida);
                            log.escribirLinea("    * Elimino " + casillaElegida + " de MovimientosProhibidos");
                        }
                        
                        if(!listaRdo.isEmpty()){
                            casillaAnterior = listaRdo.get(listaRdo.size() - 1);
                            listaRdo.remove(listaRdo.size() - 1);    
                        } else {
                            casillaAnterior = "Ninguna";
                        }
                    }
                    
                    movsCasillas = recargarMovimientos(movsCasillas, metodo);
                    
                    if (movsProhibidos.containsKey(casillaElegida)){
                        List<String> casillasProhibida = movsProhibidos.get(casillaElegida);
                        for(String casillaP: casillasProhibida){
                            if (movsCasillas.get(casillaElegida).contains(casillaP)){
                                movsCasillas.get(casillaElegida).remove(movsCasillas.get(casillaElegida).indexOf(casillaP));
                                log.escribirLinea("         * Remuevo " + casillaP + ", de los movimientos de " + casillaElegida);
                            }
                        }
                    }
                }
            }
        }
        
        if(sinSolucion){
            rdo = "No se encontró solución al tablero.";
        } else {
            rdo = "Tablero Resuelto en: " + iteraciones + " iteraciones.";
        }
        
        if (listaRdo.contains(tablero.getCasillaInicio().getCoordenada())){
            listaRdo.remove(0);
        }
        
        log.escribirLinea("");
        log.escribirLinea("----------------------------------------");
        log.escribirLinea("----------------------------------------");
        log.escribirLinea("TERMINADO");
        
        int i = 0;
        for (String c: listaRdo){
            i++;
            rdo += "\nMovimiento("+i+"): " + c;
            log.escribirLinea("    MovRDO: " + c);
        }
        return rdo;
    }

    private Map<String,List<String>> recargarMovimientos(Map<String, List<String>> movsCasillas, String metodo) {
        
        movsCasillas.clear();
        List<String> listaMovs = null;        
        
        movsCasillas.clear();
        
        //Cargo el Map con casillas y movimientos
        for(Component casilla: tablero.getCopiaPanel().getComponents()){
            if(casilla.getClass().equals(Casilla.class)){
                Casilla cas = (Casilla) casilla;
                listaMovs = movimientos.ordenarMovimientos(movimientos.getMovimientosValidos(cas.getCoordenada(), tablero, tablero.getCopiaPanel()), tablero, tablero.getCopiaPanel(), metodo);
                movsCasillas.put(cas.getCoordenada(), listaMovs);
            }
        }
        
        return movsCasillas;
    }

    private void agregarCasProhibida(String casillaAnterior, String casillaProx, Map<String,List<String>> movsProhibidos) {
        if(movsProhibidos.containsKey(casillaAnterior)){
            movsProhibidos.get(casillaAnterior).add(casillaProx);
        } else {
            List<String> array = new ArrayList<String>();
            array.add(casillaProx);
            movsProhibidos.put(casillaAnterior, array);
        }
    }

    private void iniciarLog(String metodo) {
        log.limpiar();
        log.setNombreFichero(metodo, this.getClass().getSimpleName());
        log.escribirLinea("-----------------------------------------------------------------");
        log.escribirLinea("-----------------------------------------------------------------");
        log.escribirLinea("INICIO DE LA BÚSQUEDA");
        log.escribirLinea("Metodo: " + metodo);
        log.escribirLinea("Heurística: " + this.getClass().getSimpleName());
        log.escribirLinea("");
        log.escribirLinea("");
        
    }
    
}
